package library

import (
	"encoding/json"
	"fmt"
	"github.com/robfig/cron"
	"golang.org/x/net/websocket"
	"io/ioutil"
	"strings"
	"time"
)

type BookInfo struct {
	Path      string
	BookName  string
	FileSize  int64
	Type      int //0:目录，1：文件
	FileCount int
	DirCount  int
}

//在目录中检索文档
type BookFiles struct {
	rootPath string
	Global   BookInfo
}

//创建检索文档类
func NewBookFiles() *BookFiles {
	return &BookFiles{}
}

//初始化检索文档类
func (this *BookFiles) Init(root string) {
	this.rootPath = root
	fmt.Println("book files service init ......")
	go this.staticAll()
	fmt.Println("static root path:" + this.rootPath)
	this.cron()
}

//定时任务
func (this *BookFiles) cron() {
	c := cron.New()
	c.Start() //启动cron
	//增加一个计划任务，其中 spec->“0 * * * * *” 如同linux的crontab一样
	//分别对应“秒 分 时 日 月 周”
	c.AddFunc("* 5 * * * *", func() {
		fmt.Println("static all directory starting ", time.Now())
		this.staticAll()
		fmt.Println("static all directory over! ", time.Now())
	})
}

func (this *BookFiles) search(path string, pattern string, ws *websocket.Conn) []BookInfo {
	fileList := make([]BookInfo,)
	//遍历文件夹
	ch := make(chan []BookInfo)
	go this.listDir(path, pattern, ws, ch)
	resultList := <-ch
	fmt.Println("search count:", len(resultList))
	for _, value := range resultList {
		fileList = append(fileList, value)
	}
	return fileList
}

//列出指定目录下的文件数量和目录数量
func (this *BookFiles) ViewPath(path string) ([]BookInfo, int, int) {
	fmt.Println("list path:" + this.rootPath + path)
	files, _ := ioutil.ReadDir(this.rootPath + path)
	fmt.Println("list file count:", len(files))
	FileSlice := []BookInfo{}
	dirCount := 0
	fileCount := 0
	for _, fi := range files {
		if fi.IsDir() {
			dirCount++
			FileSlice = append(FileSlice, BookInfo{path, fi.Name(), fi.Size(), 0, 0, 0})
		} else {
			fileCount++
			FileSlice = append(FileSlice, BookInfo{path, fi.Name(), fi.Size(), 1, 0, 0})
		}
	}
	return FileSlice, dirCount, fileCount
}
func (this *BookFiles) cutRoot(path string) string {
	fmt.Println("cut path, in:" + path + ",root:" + this.rootPath)
	inx := strings.Index(path, this.rootPath)
	fmt.Println("inx:", inx)
	result := path
	if inx >= 0 {
		rs := []byte(path)[inx+len(this.rootPath) : len(path)]
		fmt.Println("cut first:", rs[0])
		if rs[0] == 47 {
			result = string(rs[1:len(rs)])
		} else {
			result = string(rs)
		}
	}
	fmt.Println("cut result:" + result)
	return result
}
func (this *BookFiles) listDir(path string, pattern string, ws *websocket.Conn, ch chan []BookInfo) {
	if ws != nil {
		result := ResultMsg{0, "succ", "", nil}
		result.ResultType = 0
		result.Description = "搜索目录：" + this.cutRoot(path)
		bytes, _ := json.Marshal(&result)
		ws.Write(bytes)
	}
	fmt.Println("waiting .....  read path:" + path)
	files, _ := ioutil.ReadDir(path)
	FileSlice := []BookInfo{}
	DirSlice := []string{}
	for _, fi := range files {
		if fi.IsDir() {
			//listDir(path + "/" + fi.Name())
			DirSlice = append(DirSlice, path+"/"+fi.Name())
			//fmt.Println("dir:" + path + "/" + fi.Name())
		} else {
			//比较文件名
			if len(pattern) == 0 || strings.Contains(strings.ToUpper(fi.Name()), strings.ToUpper(pattern)) {
				bi := BookInfo{}
				bi.BookName = fi.Name()
				bi.Path = this.cutRoot(path)
				bi.Type = 1
				bi.FileSize = fi.Size()
				FileSlice = append(FileSlice, bi)
			}
		}
	}

	//find sub directory by go pattern
	DirCount := len(DirSlice)
	fmt.Println("dir len:", DirCount)
	if DirCount > 0 {
		DirCH := make([]chan []BookInfo, DirCount)
		i := 0
		for _, value := range DirSlice {
			fmt.Println("dir:" + value)
			DirCH[i] = make(chan []BookInfo)
			go this.listDir(value, pattern, ws, DirCH[i])
			i++
		}

		fmt.Println("wait routine return")
		for _, chs := range DirCH {
			//等待返回结果
			bookList := <-chs
			fmt.Println("return file count:", len(bookList))
			//将子集的结果与当前的绑定
			for _, value := range bookList {
				fmt.Println("combine file:", value.BookName)
				FileSlice = append(FileSlice, value)
			}
		}
	}
	//return results
	fmt.Println("count=", len(FileSlice))
	ch <- FileSlice //FindFiles
}
func (this *BookFiles) staticAll() {
	ch := make(chan BookInfo)
	go this.Static(this.rootPath, ch)
	this.Global = <-ch
	this.Global.Path = ""
	fmt.Println("dir count:", this.Global.DirCount, "file count:", this.Global.FileCount)

}

//统计指定目录（含子目录）下所有的文件和目录数量
func (this *BookFiles) Static(path string, ch chan BookInfo) {
	fmt.Println("read path:" + path)
	files, _ := ioutil.ReadDir(path)
	bi := BookInfo{path, "", 0, 0, 0, 0}
	dirList := []string{}
	//循环计数
	for _, fi := range files {
		if fi.IsDir() {
			bi.DirCount++
			//记录子目录
			dirList = append(dirList, path+"/"+fi.Name())
		} else {
			bi.FileCount++
			bi.FileSize += fi.Size()
		}
	}
	//发起多线程，统计子目录
	chDir := make([]chan BookInfo, len(dirList))
	i := 0
	for _, value := range dirList {
		chDir[i] = make(chan BookInfo)
		go this.Static(value, chDir[i])
		i++
	}
	//等待子目录返回结果,合并结果
	for _, ch := range chDir {
		dirInfo := <-ch
		bi.DirCount += dirInfo.DirCount
		bi.FileCount += dirInfo.FileCount
		bi.FileSize += dirInfo.FileSize
	}

	ch <- bi
}
